/**
 * OSAmI: Open Source Ambient Intelligence
 * Copyright (C) 2010 Bull S.A.S.
 * Contact: osami-general@osami-commons.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 */

package org.osami.gateway.identity.naive.internal;

import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Provides;
import org.osami.gateway.identity.Identity;
import org.osami.gateway.identity.IdentityAlreadyBoundException;
import org.osami.gateway.identity.IdentityManager;
import org.osgi.framework.Filter;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Created by IntelliJ IDEA.
 * User: guillaume
 * Date: 29 juil. 2010
 * Time: 11:12:48
 * To change this template use File | Settings | File Templates.
 */
@Component
@Provides
public class NaiveIdentityManager implements IdentityManager {

    private Map<String, Identity> identities;

    private AtomicLong idProvider;

    private Map<String, DefaultIdentity> boundIdentities;

    private FileWriter writer;

    public NaiveIdentityManager() {
        identities = new HashMap<String, Identity>();
        idProvider = new AtomicLong();
        boundIdentities = new HashMap<String, DefaultIdentity>();

        this.writer = null;
        try {
            writer = new FileWriter("NaiveIdentityManagerOutput.txt", true);

            writer.write("----------\n");
            writer.flush();
        }
        catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    public Identity createIdentity() {
        return createIdentity(null);
    }

    public Identity createIdentity(Identity parent) {

        DefaultIdentity defaultIdentity = asDefaultIdentity(parent);

        // Create the identity
        DefaultIdentity identity = new DefaultIdentity(String.valueOf(idProvider.getAndIncrement()));
        identity.setName("<No name provided>");
        if (parent != null) {
            identity.setParent(defaultIdentity);
        }
        
        // Store it
        identities.put(identity.getIdentityID(), identity);

        // XXX Keep in sync with CreateIdentityOperation !
        if (writer != null) {
            try {
                writer.write("create");
                if (defaultIdentity != null) {
                    writer.write("?parent-id=" + parent.getIdentityID());
                }
                writer.write("\n");
                writer.flush();
            }
            catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }

        // Return the Identity
        return identity;
    }

    public void removeIdentity(String id) {
        identities.remove(id);
        // XXX Keep in sync with CreateIdentityOperation !
        if (writer != null) {
            try {
                writer.write(id + "/delete\n");
                writer.flush();
            }
            catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

    public Collection<Identity> getIdentities(Filter filter) {
        // TODO implements a real solution
        return identities.values();
    }

    public Identity getIdentity(String identityId) {
        return identities.get(identityId);
    }

    public void bind(String identifier, Identity identity) throws IdentityAlreadyBoundException {

        assert (identifier != null) : "Bound Identifier is missing";
        assert (identity != null) : "Bound Identity is missing";

        DefaultIdentity defaultIdentity = asDefaultIdentity(identity);

        // Fail fast
        if (boundIdentities.containsKey(identifier)) {
            Identity bound = boundIdentities.get(identifier);
            throw new IdentityAlreadyBoundException("Identifier '" + identifier +
                    "' is already bound to Identity '" + bound.getIdentityID() + "': " + bound);
        }

        // Assign the identifier
        defaultIdentity.setBoundIdentifier(identifier);

        boundIdentities.put(identifier, defaultIdentity);

        // XXX Keep in sync with CreateIdentityOperation !
        if (writer != null) {
            try {
                writer.write(defaultIdentity.getIdentityID() + "/bind?bound-identifier=" + identifier + "\n");
                writer.flush();
            }
            catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

    private DefaultIdentity asDefaultIdentity(Identity identity) {

        if (identity == null) {
            return null;
        }

        assert (identity instanceof DefaultIdentity) : "Provided Identity type (" +
                identity.getClass() + ") comes from another IdentityProvider";

        return (DefaultIdentity) identity;
    }

    public void unbind(String identifier) {
        DefaultIdentity identity = boundIdentities.remove(identifier);
        identity.setBoundIdentifier(null);

        // XXX Keep in sync with CreateIdentityOperation !
        if (writer != null) {
            try {
                writer.write(identity.getIdentityID() + "/unbind?bound-identifier=" + identifier + "\n");
                writer.flush();
            }
            catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

    public Identity getBoundIdentity(String identifier) {
        return boundIdentities.get(identifier);
    }
}
